package su.Ner;

import iitb.CRF.CRF;
import iitb.CRF.DataIter;
import iitb.CRF.DataSequence;
import iitb.CRF.Feature;
import iitb.Model.FeatureGenImpl;
import iitb.Model.FeatureIdentifier;
import iitb.Model.FeatureImpl;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

public class CrfNer {
	public static void main(String[] args) throws Exception {
		
		FeatureGenImpl.addWholeFeature = false;   //had a problem? why pef higher than false?
		
		
		all();
		//printClusteredFeatures();
		//train();
		//printClusteredFeatures();
		//printLambda();
		//test(0);
		//printFeatures("[P]Pisanu[/P] said all three main syndicates the Sicilian [O]Mafia[/O] , or [O]Cosa Nostra[/O] ; the Calabrian ' ndrangheta and the Naples-based [O]Camorra[/O] ¡ ª have moved into the region , which traditionally is not a stronghold of the mob .");
	}


	static int maxTrainLength=50;
	public static String trainFile = "./data/train.txt";
	
	//static String testFile = root + "data/train.txt";
	
	static String testFile = "./data/test.txt";
	static String crfModelFile = "./out/model/crf.txt";
	static String FeaGenFile = ".out/model/features.txt";
	static String testOutFile = "./out/testOut.txt";

	static FeatureGenImpl train() throws Exception {
		FeatureGenImpl featureGen = getFeatureGenImpl(trainFile);
		CRF crfModel = new CRF(featureGen.numStates(), featureGen,
				new Properties());
		crfModel.train(new NerDataIter(trainFile,maxTrainLength));
		
		// save model
		crfModel.write(crfModelFile);
		return featureGen;
	}

	static FeatureGenImpl getFeatureGenImpl(String trainFile) throws Exception{
		FeatureGenImpl featureGen = new FeatureGenImpl("naive",
				NerDataSequence.labelNum,new NerDataIter(trainFile,maxTrainLength));
		featureGen.train();
		return featureGen;
	}
	
	public static CRF getCrfModel(String crfModelFile,FeatureGenImpl featureGen) throws IOException{
		CRF crfModel = new CRF(featureGen.numStates(), featureGen,
				new Properties());
		crfModel.read(crfModelFile);
		featureGen.loadMinPredicateWeight(crfModel.lambda);
		//featureGen.setMinWeight(crfModel.lambda);
			
		return crfModel;
	}
	
	static void test(long inteval) throws Exception {
		BufferedWriter bw = new BufferedWriter(new FileWriter(testOutFile));

		// prepare crf and featureGen
		FeatureGenImpl featureGen = getFeatureGenImpl(trainFile);
		CRF crfModel = getCrfModel(crfModelFile,featureGen);
		
		// count precision, recall
		int[] totalMarkedPos = new int[NerDataSequence.labelNum];
		int[] totalPos = new int[NerDataSequence.labelNum];
		int[] truePos = new int[NerDataSequence.labelNum];

		DataIter trainData = new NerDataIter(testFile,maxTestLength);
		for (trainData.startScan(); trainData.hasNext();) {
			DataSequence seq = trainData.next();
			int[] rightPath = new int[seq.length()];
			for (int i = 0; i < seq.length(); i++) {
				rightPath[i] = seq.y(i);
				// seq.set_y(i, -1); //necessary?
			}
			crfModel.apply(seq);
			// featureGen.mapStatesToLabels(seq);
			String result=seq.toString();
			bw.write( result.substring(0,result.length()-1)+ "\n");
			for (int i = 0; i < seq.length(); i++) {
				totalMarkedPos[seq.y(i)]++;
				totalPos[rightPath[i]]++;
				if (rightPath[i] == seq.y(i))
					truePos[seq.y(i)]++;
			}
		}
		printResult(totalMarkedPos, totalPos, truePos,crfModel.lambda.length,inteval);
		bw.close();

	}

	public static void printResult(int[] totalMarkedPos, int[] totalPos,
			int[] truePos, int lambdaLength,long inteval) {
		System.out.println("\n\nresult :");
		System.out.println();
		System.out.println("Label\tTrue+\tMarked+\tActual+\tPrec.\tRecall\tF1");

		System.out.print("N ");
		printResItem(totalMarkedPos, totalPos, truePos, 0);
		System.out.print("PB");
		printResItem(totalMarkedPos, totalPos, truePos, 1);
		System.out.print("PM");
		printResItem(totalMarkedPos, totalPos, truePos, 2);
		System.out.print("PE");
		printResItem(totalMarkedPos, totalPos, truePos, 3);
		System.out.print("LB");
		printResItem(totalMarkedPos, totalPos, truePos, 4);
		System.out.print("LM");
		printResItem(totalMarkedPos, totalPos, truePos, 5);
		System.out.print("LE");
		printResItem(totalMarkedPos, totalPos, truePos, 6);
		System.out.print("OB");
		printResItem(totalMarkedPos, totalPos, truePos, 7);
		System.out.print("OM");
		printResItem(totalMarkedPos, totalPos, truePos, 8);
		System.out.print("OE");
		printResItem(totalMarkedPos, totalPos, truePos, 9);
		System.out.print("TB");
		printResItem(totalMarkedPos, totalPos, truePos, 10);
		System.out.print("TM");
		printResItem(totalMarkedPos, totalPos, truePos, 11);
		System.out.print("TE");
		printResItem(totalMarkedPos, totalPos, truePos, 12);

		int correctTokens = 0, markedTokens = 0, acturalTokens = 0;
		for (int i = 1; i < NerDataSequence.labelNum; i++) {
			correctTokens += truePos[i];
			markedTokens += totalMarkedPos[i];
			acturalTokens += totalPos[i];
		}

		System.out
				.println("---------------------------------------------------------");

		double prec = (markedTokens == 0) ? 0 : U
				.truncation((double) correctTokens * 100 / markedTokens);
		double recall = (acturalTokens == 0) ? 0 : U
				.truncation((double) correctTokens * 100 / acturalTokens);
		double f =U.truncation(2 * prec * recall / (prec + recall));
		System.out.println("OV:\t" + correctTokens + "\t" + markedTokens + "\t"
				+ acturalTokens + "\t" + prec + "\t" + recall + "\t"
				+ f);
		System.out.println();
		System.out.println("data set length: "+CrfNer.maxTrainLength);
		System.out.println();
		System.out.println("test set length: "+CrfNer.maxTestLength);
		System.out.println();
		System.out.println("lambda length: "+lambdaLength);
		System.out.println();
		System.out.println(lambdaLength+"\t"+f+"\t\t"+inteval);

	}

	public static void printResItem(int[] totalMarkedPos, int[] totalPos,
			int[] truePos, int i) {
		double prec = (totalMarkedPos[i] == 0) ? 0 : U
				.truncation((double) truePos[i] * 100 / totalMarkedPos[i]);
		double recall = (totalPos[i] == 0) ? 0 : U
				.truncation((double) truePos[i] * 100 / totalPos[i]);
		System.out.println(":\t" + truePos[i] + "\t" + totalMarkedPos[i] + "\t"
				+ totalPos[i] + "\t" + prec + "\t" + recall + "\t"
				+ U.truncation(2 * prec * recall / (prec + recall)));
	}
	
	//sentence has got label.
	public static void printFeatures(String sentence) throws Exception{
		
		FeatureGenImpl fgen=getFeatureGenImpl(trainFile);
		NerDataSequence ds=new NerDataSequence(sentence);
		CRF crfModel = getCrfModel(crfModelFile,fgen);

		for (int i = 0; i < ds.length(); i++) {
			System.out.println(ds.x(i));
			for (fgen.startScanFeaturesAt(ds, i); fgen.hasNext();) {
				Feature feature=fgen.next();
				int yp = feature.y();
                int yprev = feature.yprev();
                
				if ((ds.y(i) == yp) && (((i-1 >= 0) && (yprev == ds.y(i-1))) || (yprev < 0))){
					FeatureIdentifier fi =((FeatureImpl)feature).strId;
					System.out.println(U.removeId(fi.toString())+"\t"+crfModel.lambda[(Integer) fgen.featureMap.strToInt.get(fi)]);
				}
			}
		}
		
	}
	static int maxTestLength=10000;
	public static void all() throws Exception{
		Sufei_Timer timer = new Sufei_Timer();

		timer.start();
		train();
		timer.pause();
		System.out.println();
		long interval = timer.getInterval();
		System.out.println("Time: " + interval + "   ms");
		test(interval);
		
		printClusteredFeatures();
		//printLambda();
	}

	public static void printLambda() throws Exception{
		FeatureGenImpl featureGen = getFeatureGenImpl(trainFile);
		CRF crfModel = getCrfModel(crfModelFile,featureGen);

		featureGen.printStringToInt_FeatureCountTable(crfModel.lambda);
		featureGen.printClusteredFeatures();
		
	}
	
	public static void printClusteredFeatures() throws Exception{
		FeatureGenImpl featureGen = getFeatureGenImpl(trainFile);
		featureGen.printClusteredFeatures();
	}
	
	
}